package com.jfinal.plugin.ehcache;

import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.util.StrUtil;
import com.jfinal.plugin.redis.Redis;
import com.jianjun.common.constant.CacheConstants;
import com.jianjun.common.util.AllConfig;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import redis.clients.jedis.Jedis;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

/**
 *
 * @author source
 * {@code @date} 2025/3/6 10:47
 */
@UtilityClass
public class UtilCache {
    static Boolean redisEnabled = AllConfig.CONFIG.getBoolean("redis.enabled");

    public static String get(final String key) {
        if (redisEnabled) {
            return Redis.call(j -> j.get(key));
        } else {
            String[] keySplit = key.split(CacheConstants.SPLIT_KEY);
            if (keySplit.length <= 1) {
                return CacheKit.get(CacheManager.DEFAULT_NAME, key);
            } else {
                return CacheKit.get(keySplit[0], keySplit[1]);
            }
        }
    }

    public static Boolean exists(final String key) {
        if (redisEnabled) {
            return Redis.call(j -> j.exists(key));
        } else {
            return get(key) != null;
        }
    }

    public static Long del(final String... keys) {
        if (redisEnabled) {
            return Redis.call(j -> j.del(keys));
        } else {
            for (String key : keys) {
                String[] keySplit = key.split(CacheConstants.SPLIT_KEY);
                if (keySplit.length <= 1) {
                    CacheKit.remove(CacheManager.DEFAULT_NAME, key);
                } else {
                    CacheKit.remove(keySplit[0], keySplit[1]);
                }
            }
            return (long) keys.length;
        }
    }


    public static String set(final String key, final String value) {
        if (redisEnabled) {
            return Redis.call(j -> j.set(key, value));
        } else {
            String[] keySplit = key.split(CacheConstants.SPLIT_KEY);
            if (keySplit.length <= 1) {
                CacheKit.put(CacheManager.DEFAULT_NAME, key, value);
            } else {
                if (!CacheKit.getCacheManager().cacheExists(keySplit[0])) {
                    CacheKit.getCacheManager().addCache(keySplit[0]);
                }
                CacheKit.put(keySplit[0], keySplit[1], value);
            }
            return value;
        }
    }

    public static String setex(final String key, final long seconds, final String value) {
        if (redisEnabled) {
            return Redis.call(j -> j.setex(key, seconds, value));
        } else {
            String[] keySplit = key.split(CacheConstants.SPLIT_KEY);
            if (keySplit.length <= 1) {
                CacheKit.put(CacheManager.DEFAULT_NAME, key, value);
                CacheKit.getOrAddCache(CacheManager.DEFAULT_NAME).get(key).setTimeToIdle((int) seconds);
            } else {
                if (!CacheKit.getCacheManager().cacheExists(keySplit[0])) {
                    CacheKit.getCacheManager().addCache(keySplit[0]);
                }
                CacheKit.put(keySplit[0], keySplit[1], value);
                CacheKit.getOrAddCache(keySplit[0]).get(keySplit[1]).setTimeToIdle((int) seconds);
            }
            return value;
        }
    }


    public static Set<String> keys(final String pattern) {
        if (redisEnabled) {
            return Redis.call(j -> j.keys(pattern));
        } else {
            String[] keySplit = pattern.split(CacheConstants.SPLIT_KEY);
            if (keySplit.length <= 1) {
                Collection<?> cacheKeys = CacheKit.getKeys(CacheManager.DEFAULT_NAME);
                return cacheKeys.stream()
                        .map(StrUtil::toString)
                        .collect(Collectors.toSet());
            } else {
                if (!CacheKit.getCacheManager().cacheExists(keySplit[0])) {
                    CacheKit.getCacheManager().addCache(keySplit[0]);
                }
                Collection<?> cacheKeys = CacheKit.getKeys(keySplit[0]);
                return cacheKeys.stream()
                        .map(o -> keySplit[0] + CacheConstants.SPLIT_KEY + StrUtil.toString(o))
                        .filter(StrUtil::isNotBlank)
                        .collect(Collectors.toSet());
            }
        }
    }

    public static void clear(final String pattern) {
        if (redisEnabled) {
            Set<String> cacheKeys = keys(pattern);
            del(cacheKeys.toArray(new String[0]));
        } else {
            String[] keySplit = pattern.split(CacheConstants.SPLIT_KEY);
            if ("*".equals(pattern)) {
                CacheKit.getCacheManager().clearAll();
            } else if (keySplit.length <= 1) {
                CacheKit.removeAll(CacheManager.DEFAULT_NAME);
            } else {
                if (!CacheKit.getCacheManager().cacheExists(keySplit[0])) {
                    CacheKit.getCacheManager().addCache(keySplit[0]);
                }
                CacheKit.removeAll(keySplit[0]);
            }
        }
    }

    @SneakyThrows
    public static String info() {
        if (redisEnabled) {
            return Redis.call(Jedis::info);
        } else {
            long usedMemoryHuman = 0;
            //完整包才能统计
//            String[] cacheNames = CacheKit.getCacheManager().getCacheNames();
//            for (String cacheName : cacheNames) {
//                Ehcache cache = CacheKit.getCacheManager().getEhcache(cacheName);
//                usedMemoryHuman += cache.getStatistics().getLocalHeapSizeInBytes();
//                usedMemoryHuman += cache.getStatistics().getLocalDiskSizeInBytes();
//                usedMemoryHuman += cache.getStatistics().getLocalOffHeapSizeInBytes();
//            }
            Properties info = new Properties();
            info.setProperty("used_memory_human", DataSizeUtil.format(usedMemoryHuman));
            StringWriter writer = new StringWriter();
            info.store(writer, null);
            return writer.toString();
        }
    }

    @SneakyThrows
    public static List<Map<String, String>> commandstats() {
        if (redisEnabled) {
            Properties commandStats = new Properties();
            commandStats.load(new StringReader(Redis.call(j -> j.info("commandstats"))));
            List<Map<String, String>> pieList = new ArrayList<>();
            commandStats.stringPropertyNames().forEach(key -> {
                Map<String, String> data = new HashMap<>(2);
                String property = commandStats.getProperty(key);
                data.put("name", StrUtil.removeAllPrefix(key, "cmdstat_"));
                data.put("value", StrUtil.subBetween(property, "calls=", ",usec"));
                pieList.add(data);
            });
            return pieList;
        } else {
            long getCount = 0, putCount = 0, missCount = 0;
            //完整包才能统计
//            String[] cacheNames = CacheKit.getCacheManager().getCacheNames();
//            for (String cacheName : cacheNames) {
//                Ehcache cache = CacheKit.getCacheManager().getEhcache(cacheName);
//                getCount += cache.getStatistics().getExtended().allGet().count().value();
//                putCount += cache.getStatistics().getExtended().allPut().count().value();
//                missCount += cache.getStatistics().getExtended().allMiss().count().value();
//            }
            Properties commandStats = new Properties();
            commandStats.setProperty("get", String.valueOf(getCount));
            commandStats.setProperty("put", String.valueOf(putCount));
            commandStats.setProperty("miss", String.valueOf(missCount));
            List<Map<String, String>> pieList = new ArrayList<>();
            commandStats.stringPropertyNames().forEach(key -> pieList.add(new HashMap<String, String>() {{
                put("name", key);
                put("value", commandStats.getProperty(key));
            }}));
            return pieList;
        }
    }

    public static Long dbSize() {
        if (redisEnabled) {
            return Redis.call(Jedis::dbSize);
        } else {
            long size = 0L;
            String[] cacheNames = CacheKit.getCacheManager().getCacheNames();
            for (String cacheName : cacheNames) {
                Ehcache cache = CacheKit.getCacheManager().getEhcache(cacheName);
                size += cache.getSize();
            }
            return size;
        }
    }
}
